package modeling;


/**
 * @author Mathieu Rousseau
 * @email mathieu.rousseau3@mail.mcgill.ca
 */


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;


/*  start of class RenumberFragments  */
public class RenumberFragments{
	
	
	/*  global variables  */
	private static String filename;
	private static final String inputPath = "RenumberFragments/Input/";
	private static final String outputputPath = "RenumberFragments/Output/";
	private static ArrayList<ArrayList<Double>> IFArray;
	private static ArrayList<ArrayList<Double>> indexMappings;
	/*  end of global variables  */
	
	
	/*  start of getIFs method  */
	private static void getIFs(){
		IFArray = new ArrayList<ArrayList<Double>>();
		//	open and read the IF data file
		String line = null;
		try{
			BufferedReader br = new BufferedReader(new FileReader(inputPath + filename));			
			while((line = br.readLine()) != null){
				String[] values = line.split("\t");
				if(values.length < 5){
					System.out.println("Error: there is an entry in \"" + inputPath + filename + "\" that does not have five (5) values" +
							" (i.e. index1, index2, IF, stdev, count)\nSystem.exit(0)");
					System.exit(0);
				}
				ArrayList<Double> rowEntry = new ArrayList<Double>(5);
				for(int i=0; i<5; i++){
					rowEntry.add(Double.parseDouble(values[i]));
				}
				rowEntry.trimToSize();
				IFArray.add(rowEntry);
			}
			br.close();
		}catch (IOException e) {
			e.printStackTrace();
		}
		IFArray.trimToSize();
	}
	/*  end of getIFs method  */
	
	
	/*  start of method mapFragmentIndices  */
	private static void mapFragmentIndices(){
		ArrayList<Double> fragmentIndices = new ArrayList<Double>();
		for(ArrayList<Double> rowEntry: IFArray){
			if(!fragmentIndices.contains(rowEntry.get(0))){
				fragmentIndices.add(rowEntry.get(0));
			}
			if(!fragmentIndices.contains(rowEntry.get(1))){
				fragmentIndices.add(rowEntry.get(1));
			}			
		}
		fragmentIndices.trimToSize();
		
		//	sort the fragment indices in increasing order
		Collections.sort(fragmentIndices);
		
		indexMappings = new ArrayList<ArrayList<Double>>(Collections.max(fragmentIndices).intValue() - Collections.min(fragmentIndices).intValue() + 1);
		Iterator<Double> fragIndItr = fragmentIndices.iterator();
		while(fragIndItr.hasNext()){
			ArrayList<Double> mappingEntry = new ArrayList<Double>();
			mappingEntry.add(fragIndItr.next());
			indexMappings.add(mappingEntry);
		}
		indexMappings.trimToSize();
		
		//	fill in the missing index fragments
		for(int i=0; i<indexMappings.size(); i++){
			if(i != (indexMappings.size()-1)){									//	not the last entry in the list
				int currentEntry = indexMappings.get(i).get(0).intValue();
				int nextEntry = indexMappings.get(i+1).get(0).intValue();
				while(currentEntry != (nextEntry-1)){
					indexMappings.get(i).add((double)currentEntry+1);
					currentEntry++;
				}
			}
		}
		
		//	create a mapping array for fast renumbering
		double mappingArray[] = new double[Collections.max(fragmentIndices).intValue() + 1];
		for(int i=0; i<indexMappings.size(); i++){
			Iterator<Double> mapRowItr = indexMappings.get(i).iterator();
			while(mapRowItr.hasNext()){
				mappingArray[mapRowItr.next().intValue()] = (i+1);
			}
		}
		
		//	replace all the fragment indices by their mapped values
		Iterator<ArrayList<Double>> IFArrayItr = IFArray.iterator();
		while(IFArrayItr.hasNext()){
			ArrayList<Double> IFrowEntry = IFArrayItr.next();
			IFrowEntry.set(0, mappingArray[IFrowEntry.get(0).intValue()]);
			IFrowEntry.set(1, mappingArray[IFrowEntry.get(1).intValue()]);
		}
	}
	/*  end of method mapFragmentIndices  */
	
	
	/*  start of displayIFs method  */
	private static void displayIFs(){
		Iterator<ArrayList<Double>> IFArrayItr = IFArray.iterator();
		while(IFArrayItr.hasNext()){
			Iterator<Double> rowItr = IFArrayItr.next().iterator();
			while(rowItr.hasNext()){
				System.out.print(rowItr.next() + "\t");
			}
			System.out.println();
		}
	}
	/*  end of displayIFs method  */
	
	
	/*  start of displayMappings method  */
	private static void displayMappings(){
		for(int i=0; i<indexMappings.size(); i++){
			Iterator<Double> mapRowItr = indexMappings.get(i).iterator();
			System.out.print((i+1) + "\t<-->\t");
			while(mapRowItr.hasNext()){
				System.out.print(mapRowItr.next().intValue() + "\t");
			}
			System.out.println();
		}
	}
	/*  end of displayMappings method  */
	
		
	/*  start of method ouputFragmentMapping  */
	private static void outputFragmentMapping(){
		String fname = "";
		String ext = "";
		int mid = filename.lastIndexOf(".");
		fname = filename.substring(0,mid);
		ext = filename.substring(mid+1, filename.length());
		String outputFilename = outputputPath + fname + "_output_FragmentMapping." + ext;
		try{			
			BufferedWriter bw = new BufferedWriter(new FileWriter(outputFilename));
			for(int i=0; i<indexMappings.size(); i++){
				Iterator<Double> mapRowItr = indexMappings.get(i).iterator();
				bw.write((i+1) + "\t");
				while(mapRowItr.hasNext()){
					bw.write(mapRowItr.next().intValue() + "\t");
				}
				bw.flush();
				bw.newLine();
			}
			bw.close();
		}catch (IOException e) {
			e.printStackTrace();
		}//end of try-catch block
		System.out.println("\nOutput file: " + outputFilename);
	}
	/*  start of method ouputFragmentMapping  */
	
	
	/*  start of outputIFs method  */
	private static void outputIFs(){
		String fname = "";
		String ext = "";
		int mid = filename.lastIndexOf(".");
		fname = filename.substring(0,mid);
		ext = filename.substring(mid+1, filename.length());
		String outputFilename = outputputPath + fname + "_output_IF." + ext;		
		try{			
			BufferedWriter bw = new BufferedWriter(new FileWriter(outputFilename));
			Iterator<ArrayList<Double>> IFItr = IFArray.iterator();
			while(IFItr.hasNext()){
				ArrayList<Double> rowEntry = IFItr.next();
				for(int i=0; i<rowEntry.size(); i++){
					if((i == 0) || (i == 1) || (i == 4)){
						bw.write(rowEntry.get(i).intValue() + "\t");
					}
					else{
						bw.write(rowEntry.get(i) + "\t");
					}
				}
				bw.flush();
				bw.newLine();
			}
			bw.close();
		}catch (IOException e) {
			e.printStackTrace();
		}//end of try-catch block
		System.out.println("\nOutput file: " + outputFilename);
	}
	/*  end of outputIFs method  */
	
	
	/*  start of main method  */
	public static void main(String[] args){
		if(args.length == 1){
			filename = args[0];
		}
		else{
//			System.out.println("Error: please use the following pattern (without the quotes)\n\t\"java RenumberFragments ExperimentName.txt\"\nSystem.exit(0)");
//			System.exit(0);
			
			
			//  Dekker 2010 HiC data
			filename = "HiC_chr19_chr19.txt";
			
			//  Bioinformatics paper 2010
//			filename = "DMSO.txt";
//			filename = "PMA.txt";
			
			
			//  James 2010
//			filename = "James_2010_DMSO.txt";
//			filename = "James_2010_PMA.txt";
			
			
			//  Maria 2009
//			filename = "Maria_HoxA.txt";
//			filename = "Maria_HoxB.txt";
//			filename = "Maria_HoxC.txt";
//			filename = "Maria_HoxD.txt";
			
			
//			//	Denis 2009
			//	HoxA
//			filename = "Denis_HoxA_DMSO.txt";
//			filename = "Denis_HoxA_PMA.txt";
			
			//	GeneDesert
//			filename = "Denis_GD_DMSO.txt";
//			filename = "Denis_GD_PMA.txt";
			
			
			//	James 2008
			//	HoxA
//			filename = "James_HoxA_DMSO.txt";
//			filename = "James_HoxA_PMA.txt";
			
			//	GeneDesert
//			filename = "James_GD_DMSO.txt";
//			filename = "James_GD_PMA.txt";
		}
		
		System.out.println("Input file: " + inputPath + filename);
		
		getIFs();						//	read in the IF data from file
//		displayIFs();					//	display the IF data values to screen
		
		mapFragmentIndices();			//	map the unique fragment indices in the data so they are sequential
//		displayMappings();				//	display the fragment mapping to screen
//		displayIFs();					//	display the IF data values to screen
		outputFragmentMapping();		//	output the fragment mapping for future reference
		outputIFs();					//	output the IFs with their renumbered fragment indices
	}	
	/*  end of main method  */
}
/*  end of class RenumberFragments  */